package com.xigege.netty.protocolDesignAndAnalysis.httpProtocol;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.ReferenceCountUtil;

import java.net.InetSocketAddress;

/**
 * @author huangxi
 * @class TestHttpProtocol
 * @description TestHttpProtocol
 * @create 2022-08-25 11:26
 */
public class TestHttpProtocol {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup(2);
        try {
            ChannelFuture future = new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                            ch.pipeline().addLast(new HttpServerCodec());
                            // 以下注释的内容是观察HttpServerCodec解析细节
//                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
//                                @Override
//                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//                                    // 打印看看由HttpServerCodec处理后的msg的类型:
//                                    //   class io.netty.handler.codec.http.DefaultHttpRequest
//                                    //   class io.netty.handler.codec.http.LastHttpContent$1
//                                    // HttpServerCodec将请求解析成了两部分
//                                    //   1. HttpRequest: 包含请求行和请求头
//                                    //   2. HttpContent: 包含请求体
//                                    System.out.println(msg.getClass());
//
//                                    if (msg instanceof HttpRequest) {
//                                        // 请求行，请求头的处理逻辑
//                                    } else if (msg instanceof HttpContent) {
//                                        // 请求体的处理逻辑
//                                    }
//                                }
//                            });
                            // ChannelInboundHandlerAdapter处理请求需要考虑两种情况比较麻烦
                            // 这里使用SimpleChannelInboundHandler指定某一种特定的数据类型来处理
                            // 只有数据类型为HttpRequest的数据，这个处理器才会处理
                            ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpRequest>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
                                    // 获取请求
                                    System.out.println(msg.uri());
                                    // 构建响应
                                    DefaultFullHttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK);
                                    byte[] contentBytes = "<h1>hello, world!</h1>".getBytes();
                                    response.content().writeBytes(contentBytes);
                                    // 请求头
                                    response.headers().set(HttpHeaderNames.CONTENT_LENGTH, contentBytes.length);//content的长度
                                    // 写回响应
                                    ctx.writeAndFlush(response);
                                }
                            });
                        }
                    }).bind(new InetSocketAddress(6666));
            Channel channel = future.sync().channel();
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}
